home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / sndhrdw / bzone.c < prev    next >
C/C++ Source or Header  |  2000-04-04  |  7KB  |  299 lines

  1. /*
  2.  
  3. Battlezone sound info, courtesy of Al Kossow:
  4.  
  5. D7    motor enable            this enables the engine sound
  6. D6    start LED
  7. D5    sound enable            this enables ALL sound outputs
  8.                             including the POKEY output
  9. D4    engine rev en            this controls the engine speed
  10.                             the engine sound is an integrated square
  11.                             wave (saw tooth) that is frequency modulated
  12.                             by engine rev.
  13. D3    shell loud, soft/        explosion volume
  14. D2    shell enable
  15. D1    explosion loud, soft/    explosion volume
  16. D0    explosion enable        gates a noise generator
  17.  
  18. */
  19.  
  20. #include <math.h>
  21. #include "driver.h"
  22.  
  23.  
  24. /* Statics */
  25. static INT16 *discharge = NULL;
  26. #define EXP(charge,n) (charge ? 0x7fff - discharge[0x7fff-n] : discharge[n])
  27.  
  28. static int channel;
  29. static int latch;
  30. static int poly_counter;
  31. static int poly_shift;
  32.  
  33. static int explosion_clock;
  34. static int explosion_out;
  35. static int explosion_amp;
  36. static int explosion_amp_counter;
  37.  
  38. static int shell_clock;
  39. static int shell_out;
  40. static int shell_amp;
  41. static int shell_amp_counter;
  42.  
  43. static int motor_counter;
  44. static int motor_counter_a;
  45. static int motor_counter_b;
  46. static int motor_rate;
  47. static int motor_rate_new;
  48. static int motor_rate_counter;
  49. static int motor_amp;
  50. static int motor_amp_new;
  51. static int motor_amp_step;
  52. static int motor_amp_counter;
  53.  
  54. WRITE_HANDLER( bzone_sounds_w )
  55. {
  56.     if( data == latch )
  57.         return;
  58.  
  59.     stream_update(channel, 0);
  60.     latch = data;
  61.  
  62.     mixer_sound_enable_global_w(latch & 0x20);
  63. }
  64.  
  65. static void bzone_sound_update(int param, INT16 *buffer, int length)
  66. {
  67.     while( length-- )
  68.     {
  69.         static int last_val = 0;
  70.         int sum = 0;
  71.  
  72.         /* polynome shifter H5 and H4 (LS164) clocked with 6kHz */
  73.         poly_counter -= 6000;
  74.         while( poly_counter <= 0 )
  75.         {
  76.             int clock;
  77.  
  78.             poly_counter += Machine->sample_rate;
  79.             if( ((poly_shift & 0x0008) == 0) == ((poly_shift & 0x4000) == 0) )
  80.                 poly_shift = (poly_shift << 1) | 1;
  81.             else
  82.                 poly_shift <<= 1;
  83.  
  84.             /* NAND gate J4 */
  85.             clock = ((poly_shift & 0x7000) == 0x7000) ? 0 : 1;
  86.  
  87.             /* raising edge on pin 3 of J5 (LS74)? */
  88.             if( clock && !explosion_clock )
  89.                 explosion_out ^= 1;
  90.  
  91.             /* save explo clock level */
  92.             explosion_clock = clock;
  93.  
  94.             /* input 11 of J5 (LS74) */
  95.             clock = (poly_shift >> 15) & 1;
  96.  
  97.             /* raising edge on pin 11 of J5 (LS74)? */
  98.             if( clock && !shell_clock )
  99.                 shell_out ^= 1;
  100.  
  101.             /* save shell clock level */
  102.             shell_clock = clock;
  103.         }
  104.  
  105.         /* explosion enable: charge C14 */
  106.         if( latch & 0x01 )
  107.             explosion_amp = 32767;
  108.  
  109.         /* explosion output? */
  110.         if( explosion_out )
  111.         {
  112.             if( explosion_amp > 0 )
  113.             {
  114.                 /*
  115.                  * discharge C14 through R17 + R16
  116.                  * time constant is 10e-6 * 23000 = 0.23 seconds
  117.                  * (samples were decaying much slower: 1/4th rate? )
  118.                  */
  119.                 explosion_amp_counter -= (int)(32767 / (0.23*4));
  120.                 if( explosion_amp_counter < 0 )
  121.                 {
  122.                     int n = (-explosion_amp_counter / Machine->sample_rate) + 1;
  123.                     explosion_amp_counter += n * Machine->sample_rate;
  124.                     if( (explosion_amp -= n) < 0 )
  125.                         explosion_amp = 0;
  126.                 }
  127.             }
  128.             /*
  129.              * I don't know the amplification of the op-amp
  130.              * and feedback, so the loud/soft values are arbitrary
  131.              */
  132.             if( latch & 0x02 )    /* explosion loud ? */
  133.                 sum += EXP(0,explosion_amp)/3;
  134.             else
  135.                 sum += EXP(0,explosion_amp)/4;
  136.         }
  137.  
  138.         /* shell enable: charge C9 */
  139.         if( latch & 0x04 )
  140.             shell_amp = 32767;
  141.  
  142.         /* shell output? */
  143.         if( shell_out )
  144.         {
  145.             if( shell_amp > 0 )
  146.             {
  147.                 /*
  148.                  * discharge C9 through R14 + R15
  149.                  * time constant is 4.7e-6 * 23000 = 0.1081 seconds
  150.                  * (samples were decaying much slower: 1/4th rate? )
  151.                  */
  152.                 shell_amp_counter -= (int)(32767 / (0.1081*4));
  153.                 if( shell_amp_counter < 0 )
  154.                 {
  155.                     int n = (-shell_amp_counter / Machine->sample_rate) + 1;
  156.                     shell_amp_counter += n * Machine->sample_rate;
  157.                     if( (shell_amp -= n) < 0 )
  158.                         shell_amp = 0;
  159.                 }
  160.             }
  161.             /*
  162.              * I don't know the amplification of the op-amp
  163.              * and feedback, so the loud/soft values are arbitrary
  164.              */
  165.             if( latch & 0x08 )    /* shell loud ? */
  166.                 sum += EXP(0,shell_amp)/3;
  167.             else
  168.                 sum += EXP(0,shell_amp)/4;
  169.         }
  170.  
  171.         if( latch & 0x80 )
  172.         {
  173.             static double r0 = 1.0/1e12, r1 = 1.0/1e12;
  174.  
  175.             /* NE5555 timer
  176.              * C = 0.018u, Ra = 100k, Rb = 125k
  177.              * charge time = 0.693 * (Ra + Rb) * C = 3870us
  178.              * discharge time = 0.693 * Rb * C = 1559.25us
  179.              * freq approx. 184 Hz
  180.              * I have no idea what frequencies are coming from the NE555
  181.              * with "MOTOR REV EN" being high or low. I took 240Hz as
  182.              * higher rate and sweep up or down to the new rate in 0.25s
  183.              */
  184.             motor_rate_new = (latch & 0x10) ? 240 : 184;
  185.             if( motor_rate != motor_rate_new )
  186.             {
  187.                 /* sweep rate to new rate */
  188.                 motor_rate_counter -= (int)((240 - 184) / 0.25);
  189.                 while( motor_rate_counter <= 0 )
  190.                 {
  191.                     motor_rate_counter += Machine->sample_rate;
  192.                     motor_rate += (motor_rate < motor_rate_new) ? +1 : -1;
  193.                 }
  194.             }
  195.             motor_counter -= motor_rate;
  196.             while( motor_counter <= 0 )
  197.             {
  198.                 motor_counter += Machine->sample_rate;
  199.  
  200.                 r0 = 1.0/1e12;
  201.                 r1 = 1.0/1e12;
  202.  
  203.                 if( ++motor_counter_a == 16 )
  204.                     motor_counter_a = 6;
  205.                 if( ++motor_counter_b == 16 )
  206.                     motor_counter_b = 4;
  207.  
  208.                 if( motor_counter_a & 8 )    /* bit 3 */
  209.                     r1 += 1.0/33000;
  210.                 else
  211.                     r0 += 1.0/33000;
  212.                 if( motor_counter_a == 15 ) /* ripple carry */
  213.                     r1 += 1.0/33000;
  214.                 else
  215.                     r0 += 1.0/33000;
  216.  
  217.                 if( motor_counter_b & 8 )    /* bit 3 */
  218.                     r1 += 1.0/33000;
  219.                 else
  220.                     r0 += 1.0/33000;
  221.                 if( motor_counter_b == 15 ) /* ripple carry */
  222.                     r1 += 1.0/33000;
  223.                 else
  224.                     r0 += 1.0/33000;
  225.  
  226.                 /* new voltage at C29 */
  227.                 r0 = 1.0/r0;
  228.                 r1 = 1.0/r1;
  229.                 motor_amp_new = (int)(32767 * r0 / (r0 + r1));
  230.  
  231.                 /* charge/discharge C29 (0.47uF) */
  232.                 if( motor_amp_new > motor_amp )
  233.                     motor_amp_step = (int)((motor_amp_new - motor_amp) / (r1*0.47e-6));
  234.                 else
  235.                     motor_amp_step = (int)((motor_amp - motor_amp_new) / (r0*0.47e-6));
  236.             }
  237.             if( motor_amp != motor_amp_new )
  238.             {
  239.                 motor_amp_counter -= motor_amp_step;
  240.                 if( motor_amp_counter < 0 )
  241.                 {
  242.                     int n = (-motor_amp_counter / Machine->sample_rate) + 1;
  243.                     motor_amp_counter += n * Machine->sample_rate;
  244.                     if( motor_amp > motor_amp_new )
  245.                     {
  246.                         motor_amp -= n;
  247.                         if( motor_amp < motor_amp_new )
  248.                             motor_amp = motor_amp_new;
  249.                     }
  250.                     else
  251.                     {
  252.                         motor_amp += n;
  253.                         if( motor_amp > motor_amp_new )
  254.                             motor_amp = motor_amp_new;
  255.                     }
  256.                 }
  257.             }
  258.             sum += EXP((motor_amp<motor_amp_new),motor_amp)/3;
  259.         }
  260.  
  261.         *buffer++ = (sum + last_val) / 2;
  262.  
  263.         /* crude 75% low pass filter */
  264.         last_val = (sum + last_val * 3) / 4;
  265.     }
  266. }
  267.  
  268. int bzone_sh_start(const struct MachineSound *msound)
  269. {
  270.     int i;
  271.  
  272.     discharge = (INT16 *)malloc(32768 * sizeof(INT16));
  273.     if( !discharge )
  274.         return 1;
  275.  
  276.     for( i = 0; i < 0x8000; i++ )
  277.         discharge[0x7fff-i] = (INT16) (0x7fff/exp(1.0*i/4096));
  278.  
  279.     channel = stream_init("Custom", 50, Machine->sample_rate, 0, bzone_sound_update);
  280.     if( channel == -1 )
  281.         return 1;
  282.  
  283.     return 0;
  284. }
  285.  
  286. void bzone_sh_stop(void)
  287. {
  288.     if( discharge )
  289.         free(discharge);
  290.     discharge = NULL;
  291. }
  292.  
  293. void bzone_sh_update(void)
  294. {
  295.     stream_update(channel, 0);
  296. }
  297.  
  298.  
  299.